<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>WebRTC 音视频播放</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            text-align: center;
            margin-top: 50px;
        }
        video {
            width: 640px;
            height: 360px;
            background: black;
        }
    </style>
</head>
<body>
    <h1>WebRTC 音视频播放</h1>
    <button onclick="startPlayback()">播放音视频</button>
    <br><br>
    <video id="video" autoplay playsinline controls></video>

    <script>
        let ws;
        let peerConnection;
        let lastAudioTrackTime = 0;
        let audioTrackCount = 0;
        let videoTrackCount = 0;
        let mediaStream = new MediaStream();

        // 检查音频上下文状态
        function checkAudioContext() {
            const AudioContext = window.AudioContext || window.webkitAudioContext;
            if (AudioContext) {
                const context = new AudioContext();
                console.log("音频上下文状态:", context.state);
                if (context.state === "suspended") {
                    context.resume().then(() => console.log("音频上下文已恢复"));
                }
                return context;
            }
            console.warn("浏览器不支持 AudioContext");
            return null;
        }

        // 等待 WebSocket 连接就绪
        function waitForWebSocket(ws) {
            return new Promise((resolve, reject) => {
                if (ws.readyState === WebSocket.OPEN) {
                    resolve();
                } else {
                    ws.onopen = () => {
                        console.log("WebSocket 连接建立");
                        resolve();
                    };
                    ws.onerror = (error) => {
                        console.error("WebSocket 错误:", error);
                        reject(error);
                    };
                    setTimeout(() => {
                        if (ws.readyState !== WebSocket.OPEN) {
                            reject(new Error("WebSocket 连接超时"));
                        }
                    }, 5000);
                }
            });
        }

        async function startPlayback() {
            console.log("开始音视频播放");
            console.log("连接到 WebSocket: ws://localhost:8080/ws");

            // 检查音频上下文
            checkAudioContext();

            // 重置状态
            mediaStream = new MediaStream();
            audioTrackCount = 0;
            videoTrackCount = 0;
            lastAudioTrackTime = 0;

            ws = new WebSocket("ws://localhost:8080/ws");
            ws.onclose = () => {
                console.log("WebSocket 连接关闭，5秒后重连");
                setTimeout(startPlayback, 5000);
            };
            ws.onmessage = handleMessage;

            // WebSocket 心跳
            setInterval(() => {
                if (ws.readyState === WebSocket.OPEN) {
                    ws.send(JSON.stringify({ type: "ping" }));
                    console.log("发送 WebSocket 心跳");
                }
            }, 10000);

            try {
                await waitForWebSocket(ws);
            } catch (error) {
                console.error("WebSocket 连接失败:", error);
                setTimeout(startPlayback, 5000);
                return;
            }

            console.log("创建 RTCPeerConnection");
            peerConnection = new RTCPeerConnection({
                iceServers: [
                    { urls: "stun:stun.l.google.com:19302" },
                ]
            });

            const pendingCandidates = [];

            peerConnection.onicecandidate = (event) => {
                if (event.candidate) {
                    console.log("新 ICE 候选者:", event.candidate.candidate);
                    if (ws.readyState === WebSocket.OPEN) {
                        ws.send(JSON.stringify({
                            type: "candidate",
                            candidate: JSON.stringify(event.candidate.toJSON())
                        }));
                        console.log("已发送 ICE 候选者到服务器");
                    } else {
                        console.log("WebSocket 未就绪，缓存 ICE 候选者");
                        pendingCandidates.push(event.candidate.toJSON());
                    }
                } else {
                    console.log("ICE 候选者收集完成");
                }
            };

            peerConnection.oniceconnectionstatechange = () => {
                console.log("ICE 连接状态:", peerConnection.iceConnectionState);
                if (peerConnection.iceConnectionState === "failed" || peerConnection.iceConnectionState === "disconnected") {
                    console.log("ICE 连接失败或断开，5秒后重新开始播放");
                    peerConnection.close();
                    setTimeout(startPlayback, 5000);
                }
            };

            peerConnection.ontrack = (event) => {
                console.log("收到轨道:", event.track.kind, event.track.id);
                console.log("流:", event.streams[0]);
                const video = document.getElementById("video");

                if (event.track.kind === "audio") {
                    console.log("音频轨道启用状态:", event.track.enabled);
                    console.log("音频轨道准备状态:", event.track.readyState);
                    event.track.enabled = true;
                    mediaStream.addTrack(event.track);
                    audioTrackCount++;
                    const now = Date.now();
                    if (lastAudioTrackTime > 0) {
                        console.log("音频轨道间隔:", now - lastAudioTrackTime, "ms");
                    }
                    lastAudioTrackTime = now;
                    event.track.onunmute = () => console.log("音频轨道取消静音");
                    event.track.onmute = () => console.log("音频轨道静音，可能无数据");
                    event.track.onended = () => console.log("音频轨道结束");
                } else if (event.track.kind === "video") {
                    console.log("视频轨道启用状态:", event.track.enabled);
                    console.log("视频轨道准备状态:", event.track.readyState);
                    event.track.enabled = true;
                    mediaStream.addTrack(event.track);
                    videoTrackCount++;
                    event.track.onunmute = () => console.log("视频轨道取消静音");
                    event.track.onmute = () => console.log("视频轨道静音，可能无数据");
                    event.track.onended = () => console.log("视频轨道结束");
                }

                video.srcObject = mediaStream;
                video.volume = 1.0;
                video.muted = false;
                console.log("已更新视频元素媒体流，轨道统计:", {
                    audioTracks: mediaStream.getAudioTracks().length,
                    videoTracks: mediaStream.getVideoTracks().length
                });
                console.log("当前音频轨道数量:", audioTrackCount);
                console.log("当前视频轨道数量:", videoTrackCount);
                console.log("视频元素音量:", video.volume, "静音状态:", video.muted);
            };

            const video = document.getElementById("video");
            video.onerror = () => console.error("视频元素错误:", video.error ? video.error.message : "未知错误");
            video.oncanplay = () => console.log("视频可播放");
            video.onplaying = () => console.log("视频和音频正在播放");
            video.onwaiting = () => console.log("视频等待数据（缓冲中）");
            video.onstalled = () => console.log("视频停止，可能缺少数据");
            video.onended = () => console.log("视频播放结束");

            setInterval(async () => {
                if (peerConnection) {
                    const stats = await peerConnection.getStats();
                    stats.forEach(report => {
                        if (report.type === "inbound-rtp" && report.kind === "audio") {
                            console.log("音频 RTP 统计:", {
                                bytesReceived: report.bytesReceived || 0,
                                packetsReceived: report.packetsReceived || 0,
                                packetsLost: report.packetsLost || 0,
                                jitter: report.jitter || 0
                            });
                        } else if (report.type === "inbound-rtp" && report.kind === "video") {
                            console.log("视频 RTP 统计:", {
                                bytesReceived: report.bytesReceived || 0,
                                packetsReceived: report.packetsReceived || 0,
                                packetsLost: report.packetsLost || 0
                            });
                        }
                    });
                }
                if (video.buffered.length > 0) {
                    console.log("缓冲范围:", video.buffered.start(0), "-", video.buffered.end(0));
                    console.log("当前时间:", video.currentTime);
                }
                console.log("视频分辨率:", video.videoWidth, "x", video.videoHeight);
            }, 5000);

            console.log("创建 Offer");
            try {
                const offer = await peerConnection.createOffer({
                    offerToReceiveVideo: true,
                    offerToReceiveAudio: true
                });
                console.log("Offer 创建:", offer.sdp.substring(0, 200) + "...");
                await peerConnection.setLocalDescription(offer);
                console.log("设置本地描述");

                if (ws.readyState === WebSocket.OPEN) {
                    ws.send(JSON.stringify({
                        sdp: btoa(peerConnection.localDescription.sdp),
                        type: "offer"
                    }));
                    console.log("已发送 Offer 到服务器");

                    // 发送缓存的 ICE 候选者
                    for (const candidate of pendingCandidates) {
                        ws.send(JSON.stringify({
                            type: "candidate",
                            candidate: JSON.stringify(candidate)
                        }));
                        console.log("已发送缓存的 ICE 候选者:", candidate.candidate);
                    }
                    pendingCandidates.length = 0;
                } else {
                    console.error("WebSocket 未就绪，无法发送 Offer");
                    peerConnection.close();
                    setTimeout(startPlayback, 5000);
                }
            } catch (error) {
                console.error("创建 Offer 错误:", error);
                peerConnection.close();
                setTimeout(startPlayback, 5000);
            }
        }

        function handleMessage(event) {
            console.log("收到 WebSocket 消息:", event.data);
            try {
                const signal = JSON.parse(event.data);
                switch (signal.type) {
                    case "answer":
                        console.log("收到服务器的 Answer");
                        const sdp = atob(signal.sdp);
                        console.log("Answer SDP:", sdp.substring(0, 200) + "...");
                        peerConnection.setRemoteDescription({
                            type: "answer",
                            sdp: sdp
                        }).then(() => {
                            console.log("成功设置远程描述");
                        }).catch(err => {
                            console.error("设置远程描述错误:", err);
                        });
                        break;
                    case "candidate":
                        console.log("收到服务器的 ICE 候选者");
                        try {
                            const candidate = JSON.parse(signal.candidate);
                            peerConnection.addIceCandidate(new RTCIceCandidate(candidate))
                                .then(() => console.log("成功添加 ICE 候选者"))
                                .catch(err => console.error("添加 ICE 候选者错误:", err));
                        } catch (err) {
                            console.error("解析 ICE 候选者错误:", err);
                        }
                        break;
                    case "error":
                        console.log("收到服务器错误:", signal.sdp);
                        console.log("因服务器错误，5秒后重新开始播放");
                        peerConnection.close();
                        setTimeout(startPlayback, 5000);
                        break;
                    case "ping":
                        console.log("收到服务器心跳");
                        ws.send(JSON.stringify({ type: "pong" }));
                        break;
                    case "pong":
                        console.log("收到服务器心跳响应");
                        break;
                    default:
                        console.log("未知消息类型:", signal.type);
                }
            } catch (error) {
                console.error("解析 WebSocket 消息错误:", error);
            }
        }
    </script>
</body>
</html>